package nl.boektrust.btsoep.client;

import java.util.Date;
import java.util.List;
import java.util.Set;

import nl.boektrust.btsoep.shared.model.AvailabilityCode;
import nl.boektrust.btsoep.shared.model.Person;
import nl.boektrust.btsoep.shared.model.PhysicalBookManifestation;
import nl.boektrust.btsoep.shared.model.Price;
import nl.boektrust.btsoep.shared.model.PriceTypeCode;
import nl.boektrust.btsoep.shared.model.ProductFormCode;
import nl.boektrust.btsoep.shared.model.EditionTypeCode;
import nl.boektrust.btsoep.shared.model.SupplierCode;
import nl.boektrust.btsoep.shared.model.SupplyDetail;

import com.google.gwt.cell.client.DateCell;
import com.google.gwt.cell.client.TextCell;
import com.google.gwt.core.client.GWT;
import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.event.dom.client.KeyPressEvent;
import com.google.gwt.event.dom.client.KeyPressHandler;
import com.google.gwt.event.dom.client.KeyUpEvent;
import com.google.gwt.event.dom.client.KeyUpHandler;
import com.google.gwt.user.cellview.client.CellTable;
import com.google.gwt.user.cellview.client.Column;
import com.google.gwt.user.cellview.client.SimplePager;
import com.google.gwt.user.cellview.client.SimplePager.TextLocation;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.PopupPanel;
import com.google.gwt.user.client.ui.TextBox;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;
import com.google.gwt.view.client.ListDataProvider;
import com.google.gwt.view.client.MultiSelectionModel;
import com.google.gwt.view.client.ProvidesKey;
import com.google.gwt.view.client.SelectionChangeEvent;

public class BoekenPanel extends VerticalPanel implements ClickHandler, KeyUpHandler {
	Btsoep btsoep;
	Button filterBoekButton = new Button("Filter");
	Button newBoekButton = new Button("Nieuw");
	Button editBoekButton = new Button("Bewerk");
	Button deleteBoekButton = new Button("Verwijder");
	TextBox topTextBox = new TextBox();
	PersistentServiceAsync persistentService;
	ListDataProvider<PhysicalBookManifestation> dataProvider;
	static int minimumFilterLength = 3;
	final WaitPopup waitPopup = new WaitPopup();
	final Label feedbackLabel = new Label("");
	

	private static class ErrorPopup extends PopupPanel {

	    public ErrorPopup() {
	      // PopupPanel's constructor takes 'auto-hide' as its boolean parameter.
	      // If this is set, the panel closes itself automatically when the user
	      // clicks outside of it.
	      super(true);
	      this.setGlassEnabled(true);

	      // PopupPanel is a SimplePanel, so you have to set it's widget property to
	      // whatever you want its contents to be.
	      setWidget(new Label("Error: filter moet minimaal "+minimumFilterLength+" cijfers (bv. '97890626') zijn."));
	    }
	  }
	
	private static class WaitPopup extends PopupPanel {

	    public WaitPopup() {
	      // PopupPanel's constructor takes 'auto-hide' as its boolean parameter.
	      // If this is set, the panel closes itself automatically when the user
	      // clicks outside of it.
	      super(true);
	      this.setGlassEnabled(true);

	      // PopupPanel is a SimplePanel, so you have to set it's widget property to
	      // whatever you want its contents to be.
	      setWidget(new Label("Inladen gegevens, wacht aub."));
	    }
	  }
	
	public BoekenPanel(Btsoep btsoep) {
		persistentService = GWT.create(PersistentService.class);
		this.btsoep = btsoep;

		// Instantiate the interfaces to access methods in the interface
		this.buildTopPanel();
		this.add(feedbackLabel);
		this.buildTable();
	}
	
	
	
	
	public void populateBooksArray(ListDataProvider<PhysicalBookManifestation> dataProvider) {
		final List<PhysicalBookManifestation> list = dataProvider.getList();
		try {
			String pattern = topTextBox.getText();
			System.out.println("getBooksByISBN: looking up books, pattern: "+pattern);
			if (pattern.length() < 4) {
			    
				return;
			}
			
			waitPopup.show();
			persistentService.getBooksByISBN(pattern, new AsyncCallback<List<PhysicalBookManifestation>>() {
				//		@Override
				public void onFailure(Throwable caught) {
					System.out.println("BoekenPanel.java:populateBooksArray(): onClick(): PersistentService RPC call failed " + caught);
					waitPopup.hide();
				}

				//      @Override
				public void onSuccess(List<PhysicalBookManifestation> result) {
					
					System.out.println("getBooksByISBN: success");
					System.out.println("BoekenPanel.java: PersistentService RPC call succeeded; received a list with "+result.size()+" elements");
					 
					list.clear();
					for (PhysicalBookManifestation book : result) {
						book.setSelected(false);
						list.add(book);
					}
					waitPopup.hide();

					//Log.debug("in onSuccess, personList has " + personList.size() + " elements");
				}

			});
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void loadData() {
	    populateBooksArray(dataProvider);
	}
	
	public void onClick(ClickEvent event) {
	    // note that in general, events can have sources that are not Widgets.
	    Widget sender = (Widget) event.getSource();

	    if (sender == editBoekButton) {
	    	feedbackLabel.setText("Bewerken, even wachten aub (opvragen boekgegevens).");
	      // handle b1 being clicked
			final List<PhysicalBookManifestation> list = dataProvider.getList();
			for (PhysicalBookManifestation b: list) {
				if (b.isSelected()==true) {
			    	feedbackLabel.setText("Bewerken, even wachten aub (opbouwen scherm).");
		        	EditBookDialog editBookDialogBox = new EditBookDialog(b, this);
		        	editBookDialogBox.show();
			    	feedbackLabel.setText("");

				}
			}
	    } else if (sender == newBoekButton) {
			editBoekButton.setEnabled(false);
			deleteBoekButton.setEnabled(false);
			System.out.println("Clicked on newBoekButton");

			PhysicalBookManifestation bookmf = new PhysicalBookManifestation();
			System.out.println("Allocated new bookmf");
			bookmf.setFirstModificationDate(new Date());
			System.out.println("bookmf.setFirstModificationDate(new Date());");

        	EditBookDialog editBookDialog = new EditBookDialog(bookmf, this);
			System.out.println("EditBookDialog editBookDialog = new EditBookDialog(bookmf, this);");

        	editBookDialog.parentPanel = this;
        	editBookDialog.show();
			System.out.println("editBookDialog.show();");


	    } else if (sender == filterBoekButton) {
	    	if (topTextBox.getText().length() >= minimumFilterLength) {
	    		loadData();
	    	}
	    } else if (sender == deleteBoekButton) {
			final List<PhysicalBookManifestation> list = dataProvider.getList();
			for (PhysicalBookManifestation b: list) {
				final PhysicalBookManifestation aBook = b;
				if (b.isSelected()==true) {
					try {
						persistentService.deletePhysicalBookManifestation(b, new AsyncCallback<Void>() {
							//		@Override
							public void onFailure(Throwable caught) {
								System.err.println("Error deleting book.");
							}
							//      @Override
							public void onSuccess(Void result) {
								System.err.println("Success deleting book.");
								list.remove(aBook);
							}
						});
					} catch (Exception e) {
						e.printStackTrace();
					}
				}
			}

	    }
	  }
	
	
	public void onKeyUp(KeyUpEvent event) {
	    Widget sender = (Widget) event.getSource();
	    if (sender == topTextBox) {
	    	if (((TextBox)sender).getValue().length() >= minimumFilterLength) {
	    		this.filterBoekButton.setEnabled(true);
	    	} else {
	    		this.filterBoekButton.setEnabled(false);
	    	}
	    }
	
	}
	 /**
	   * The key provider that allows us to identify Contacts even if a field
	   * changes. We identify contacts by their unique ID.
	   */
	  private static final ProvidesKey<PhysicalBookManifestation> KEY_PROVIDER = new ProvidesKey<PhysicalBookManifestation>() {
	    public Object getKey(PhysicalBookManifestation item) {
	      return item.getId();
	    }
	  };
	
	private void buildTable() {
		//ScrollPanel sp = new ScrollPanel();
		// Create a celltable
		final CellTable<PhysicalBookManifestation> bookTable = new CellTable<PhysicalBookManifestation>(KEY_PROVIDER);
		// Create name column
	    final TextCell nameCell = new TextCell();
	  
	 
	    
		Column<PhysicalBookManifestation, String> publisherColumn = new Column<PhysicalBookManifestation, String>(new TextCell()) {
			@Override
			public String getValue(PhysicalBookManifestation bookmf) {
				if (bookmf.getPublisher() != null && bookmf.getPublisher().getName() != null) {
					return bookmf.getPublisher().getName();
				} 
				return "?";
			}
		};
		bookTable.addColumn(publisherColumn, "Uitgever");

		Column<PhysicalBookManifestation, String> isbn13Column = new Column<PhysicalBookManifestation, String>(new TextCell()) {
			@Override
			public String getValue(PhysicalBookManifestation bookmf) {
				try {
					return bookmf.getIsbn().getIsbn13();
				} catch (Exception e) {
					System.err.println("BoekenPanel:buildTable(): while building ISBN column: getIsbn().getIsbn13() is NULL (should be initialized)");
				}
				return "";
			}
		};
		bookTable.addColumn(isbn13Column, "ISBN");

		Column<PhysicalBookManifestation, String> nameColumn = new Column<PhysicalBookManifestation, String>(nameCell) {
			@Override
			public String getValue(PhysicalBookManifestation bookmf) {
				return bookmf.getTitle();
			}
		};
		/*nameColumn.setFieldUpdater(new FieldUpdater<Person,String>() {
			public void update(int index, Person object, String value) {
				System.out.println("field updater called");
		       // pendingChanges.add(new FirstNameChange(object, value));
		      }
		});*/
		// Make the name column sortable.
	   // nameColumn.setSortable(true);
	    //personTable.setKeyboardSelectionPolicy(KeyboardSelectionPolicy.ENABLED);
		bookTable.addColumn(nameColumn, "Titel");

		Column<PhysicalBookManifestation, String> productFormColumn = new Column<PhysicalBookManifestation, String>(new TextCell()) {
			@Override
			public String getValue(PhysicalBookManifestation bookmf) {
				String value = new String("");
				if (bookmf.getProductFormCode() != null && bookmf.getProductFormCode() != ProductFormCode.UNDEFINED) {
					value = value + ProductFormCode.stringValue(bookmf.getProductFormCode());
				}
				if (bookmf.getEditionTypeCode() != null && bookmf.getEditionTypeCode() != EditionTypeCode.UNDEFINED) {
					if (value.length() > 0) value = value+", ";
					value = value + EditionTypeCode.stringValue(bookmf.getEditionTypeCode());
				}
				if (bookmf.getEdition() != -1) {
					if (value.length() > 0) value = value+", ";

					value = value + bookmf.getEdition()+"e druk";
				}
				return value;
			}
		};
		bookTable.addColumn(productFormColumn, "Druk, etc.");

		Column<PhysicalBookManifestation, String> availabilityColumn = new Column<PhysicalBookManifestation, String>(new TextCell()) {
			@Override
			public String getValue(PhysicalBookManifestation bookmf) {
				String value = new String("");
				String longvalue = new String("");
				if (bookmf.getSupplyDetails() != null) {
					for (SupplyDetail s : bookmf.getSupplyDetails()) {
						if (s.getAvailabilityCode() != AvailabilityCode.UNDEFINED) {
							String supplierCode = "?";
							
							if (s.getSupplier().getSupplierCode() != null) {
								
								switch (s.getSupplier().getSupplierCode()) {
								case PUBLISHER: 
									supplierCode = "U";
									break; 
								case CENTRAALBOEKHUIS: 
									supplierCode = "CB";
									break; 
								case SCHOLTENS: 
									supplierCode = "S";
									break; 
								case LIBRIS: 
									supplierCode = "L";
									break; 
								}
							} else {
								if (s.getSupplier().getName().equals("Uitgever")) {
									supplierCode = "U";
								} else if (s.getSupplier().getName().equals("Centraal Boekhuis")) {
									supplierCode = "CB";
								} else if (s.getSupplier().getName().equals("Scholtens")) {
									supplierCode = "S";
								} else if (s.getSupplier().getName().equals("Libris")) {
									supplierCode = "L";
								} else {
									supplierCode = s.getSupplier().getName();
								}
							}
							longvalue = value + s.getSupplier().getName() + ": "+AvailabilityCode.stringValue(s.getAvailabilityCode())+"; ";
							value = value + supplierCode + ": "+AvailabilityCode.stringValueForOnix(s.getAvailabilityCode())+"; ";
							
						}
					}
				}
				return value;
			}
		};
		bookTable.addColumn(availabilityColumn, "Beschikbaarheid");
		
		Column<PhysicalBookManifestation, String> priceColumn = new Column<PhysicalBookManifestation, String>(new TextCell()) {
			@Override
			public String getValue(PhysicalBookManifestation bookmf) {
				if (bookmf.getPrice(PriceTypeCode.MSRP) > 0) {
					return Price.toString(bookmf.getFixedBookPriceAmountInCents())+" / "+bookmf.getPriceAsString(PriceTypeCode.MSRP);
				}
				return bookmf.getPriceAsString(PriceTypeCode.FIXED);
			}
		};
		bookTable.addColumn(priceColumn, "Vaste/advies boekenprijs");

		Column<PhysicalBookManifestation, String> contentsColumn = new Column<PhysicalBookManifestation, String>(new TextCell()) {
			@Override
			public String getValue(PhysicalBookManifestation bookmf) {
				return bookmf.getTitle();
			}
		};
		bookTable.addColumn(contentsColumn, "Inhoud");
		

		Column<PhysicalBookManifestation, Date> dateLastChangedColumn = new Column<PhysicalBookManifestation, Date>(new DateCell()) {
			@Override
			public Date getValue(PhysicalBookManifestation bookmf) {
				return bookmf.getModificationDate();
			}
		};
		bookTable.addColumn(dateLastChangedColumn, "Mutatiedatum (laatste)");

		Column<PhysicalBookManifestation, Date> dateFirstChangedColumn = new Column<PhysicalBookManifestation, Date>(new DateCell()) {
			@Override
			public Date getValue(PhysicalBookManifestation bookmf) {
				return bookmf.getFirstModificationDate();
			}
		};
		bookTable.addColumn(dateFirstChangedColumn, "Mutatiedatum (eerste)");
		/**/
		// Create a data provider.
	    dataProvider = new ListDataProvider<PhysicalBookManifestation>();

	    // Connect the table to the data provider.
	    dataProvider.addDataDisplay(bookTable);

	    // Add the data to the data provider, which automatically pushes it to the
	    // widget.
	    List<PhysicalBookManifestation> list = dataProvider.getList();
	    loadData();
	    
	    final MultiSelectionModel<PhysicalBookManifestation> selectionModel = new MultiSelectionModel<PhysicalBookManifestation>();
	    bookTable.setSelectionModel(selectionModel);
	    selectionModel.addSelectionChangeHandler(new SelectionChangeEvent.Handler() {
		      public void onSelectionChange(SelectionChangeEvent event) {
		    	  
		    	  Set<PhysicalBookManifestation> selectedSet = selectionModel.getSelectedSet();
		    	  
		    	  if (selectedSet.size() == 0) {
	    			  editBoekButton.setEnabled(false);
		    		  deleteBoekButton.setEnabled(false);
		    	  } else {
		    		  // determine which persons are selected
		    		  List<PhysicalBookManifestation> list = dataProvider.getList();
		    		  for (PhysicalBookManifestation p : list) {
			    		  if (selectedSet.contains(p)) {
			    			  p.setSelected(true);
			    		  } else {
			    			  p.setSelected(false);
			    		  }
			    	  }
		    		  // reset state of the buttons. 
		    		  if (selectedSet.size() == 1) editBoekButton.setEnabled(true); else editBoekButton.setEnabled(false);
		    		  if (selectedSet.size() >= 1) deleteBoekButton.setEnabled(true);
		    	  }
		    	  //Person selected = selectionModel.getSelectedObject();
		    	  //if (selected != null) {
		    		//  EditMensDialog editMensDialogBox = new EditMensDialog(selected, mensenPanel);
		    		 // editMensDialogBox.show();
		    	  //}
		      }
		    });
	
	    //personTable.setSelectionModel(selectionModel);
	    /*
	    DefaultSelectionEventManager<Person> selectionEventManager = DefaultSelectionEventManager.createCustomManager(new DefaultSelectionEventManager.CheckboxEventTranslator<Person>() {
	    	@Override
	    	public SelectAction translateSelectionEvent(CellPreviewEvent<Person> event) {
                SelectAction action = super.translateSelectionEvent(event);
                if (action.equals(SelectAction.IGNORE)) {
                    GWT.log("DO WHAT YOU WANT!!!");
                    return SelectAction.IGNORE;
                }
                return action;
            }
	    });
	    personTable.setSelectionModel(selectionModel, selectionEventManager);
	    */
	   /* */

	    // add a pager
	    SimplePager pager;
	    SimplePager.Resources pagerResources = GWT.create(SimplePager.Resources.class);
	    pager = new SimplePager(TextLocation.CENTER, pagerResources, true, 0,true);
	    pager.setDisplay(bookTable);
	    pager.setPageSize(25);
	    // Add a ColumnSortEvent.ListHandler to connect sorting to the
	    // java.util.List.
	    /*
	    ListHandler<BookManifestation> columnSortHandler = new ListHandler<BookManifestation>(list);
	    columnSortHandler.setComparator(booksColumn, new Comparator<BookManifestation>() {
	    	public int compare(BookManifestation o1, BookManifestation o2) {
	    		return 0;
	    		//if (o1.get == o2) return 0;
	    		//if (o1 > o2) return 1; else return -1;
	    	}
	    });
	    columnSortHandler.setComparator(nameColumn,
	    		new Comparator<BookManifestation>() {
	    	public int compare(BookManifestation o1, BookManifestation o2) {
	    		String o1Key = o1.lastPartOfName();
	    		if (o1.getName().length() > o1Key.length()) o1Key += o1.getName();
	    		String o2Key = o2.lastPartOfName();
	    		if (o2.getName().length() > o2Key.length()) o2Key += o2.getName();

	    		if (o1 == o2) {
	    			return 0;
	    		}

	    		// Compare the name columns.
	    		if (o1 != null) {
	    			return (o2 != null) ? o1Key.compareTo(o2Key) : 1;
	    		}
	    		return -1;
	    	}
	    });
	    bookTable.addColumnSortHandler(columnSortHandler);
	    */

	    // We know that the data is sorted alphabetically by default.
	    bookTable.getColumnSortList().push(nameColumn);
	    this.add(bookTable);
	    this.add(pager);

		//todo: http://code.google.com/p/google-web-toolkit-incubator/wiki/PagingScrollTable
	}
	
	private void buildTopPanel() {
		HorizontalPanel topPanel = new HorizontalPanel();
		/* add the 'new' button */
		newBoekButton.addClickHandler(this);
		deleteBoekButton.addClickHandler(this);
		editBoekButton.addClickHandler(this);
		filterBoekButton.addClickHandler(this);
		topTextBox.addKeyUpHandler(this);
		
		topPanel.add(new Label("Selectie: "));
		topPanel.add(topTextBox);
		topPanel.add(filterBoekButton);
		topPanel.add(newBoekButton);
		topPanel.add(editBoekButton);
		topPanel.add(deleteBoekButton);
		editBoekButton.setEnabled(false);
		deleteBoekButton.setEnabled(false);
		filterBoekButton.setEnabled(false);
		this.add(topPanel);
	}

}
